package br.com.minhasfinancas.fw.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;

import org.primefaces.component.datatable.DataTable;

import br.com.minhasfinancas.fw.interfaces.CrudManager;
import br.com.minhasfinancas.fw.util.GenericsReader;
import br.com.minhasfinancas.fw.util.JSFUtil;

public abstract class AbstractBean<E, ID> implements Serializable {

	private static final long serialVersionUID = 1L;

	private DataModel<E> dataModel;

	private DataTable dataTable;

	private Class<E> entityClass;

	@PersistenceContext
	private EntityManager entityManager;

	private String id;

	private Class<ID> idClass;

	private E instance;

	private String name;

	private List<E> resultList = null;

	private boolean autoSearch = false;

	public abstract String getEditView();

	public abstract String getListView();

	protected void clearDataModel() {
		this.dataModel = null;
	}

	@SuppressWarnings("unchecked")
	protected ID convert(final String i) {
		if (this.getIDClass() == Integer.class) {
			return (ID) Integer.valueOf(i);
		} else if (this.getIDClass() == Long.class) {
			return (ID) Long.valueOf(i);
		} else if (this.getIDClass() == Double.class) {
			return (ID) Double.valueOf(i);
		} else if (this.getIDClass() == Float.class) {
			return (ID) Float.valueOf(i);
		} else if (this.getIDClass() == String.class) {
			return (ID) i;
		} else {
			return null;
		}
	}

	public E getInstance() {
		if (this.instance == null) {
			if (this.isManaged()) {
				this.instance = this.loadInstance();
			} else {
				this.instance = this.createInstance();
			}
		}
		return this.instance;
	}

	private E createInstance() {
		return this.newInstance();
	}

	public E newInstance() {
		try {
			return this.getEntityClass().newInstance();
		} catch (final Exception e) {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	private Class<E> getEntityClass() {
		if (this.entityClass == null) {
			this.entityClass = (Class<E>) GenericsReader.getTypeArgument(
					this.getClass(), 0);
		}
		return this.entityClass;
	}

	public CrudManager<E, ID> getCrudManager() {
		return null;
	}

	// public DataModel<E> getDataModel() {
	// if (this.dataModel == null) {
	// if (this.isAutoSearch() || (this.resultList != null)) {
	// this.resultList = this.handleResultList();
	// }
	//
	// if (this.resultList == null) {
	// this.resultList = new ArrayList<E>();
	// }
	//
	// this.dataModel = new ListDataModel<E>(this.resultList);
	// }
	//
	// return this.dataModel;
	// }

	public DataTable getDataTable() {
		return this.dataTable;
	}

	public String getId() {
		if (((this.id == null) || this.id.isEmpty())
				&& JSFUtil.getRequestParameter("id") != null) {
			this.id = JSFUtil.getRequestParameter("id");
		}
		return this.id;
	}

	@SuppressWarnings("unchecked")
	private Class<ID> getIDClass() {
		if (this.idClass == null) {
			this.idClass = (Class<ID>) GenericsReader.getTypeArgument(
					getClass(), 1);
		}
		return this.idClass;
	}

	public String getName() {
		if (this.name == null) {
			this.name = String.valueOf(getClass().getSimpleName().charAt(0))
					.toLowerCase() + getClass().getSimpleName().substring(1);
		}
		return this.name;
	}

	public List<E> getResultList() {
		return this.resultList;
	}

	public abstract List<E> handleResultList();

	public boolean isManaged() {
		return (this.getId() != null) && !"".equals(this.getId());
	}

	public E loadInstance() {
		if (this.getCrudManager() != null) {
			return this.getCrudManager().obter(this.convert(this.id));
		} else {
			return this.entityManager.find(this.getEntityClass(),
					this.convert(this.getId()));
		}
	}

	public String merge() {
		try {
			if (this.getCrudManager() != null) {
				this.getCrudManager().alterar(this.getInstance());
			} else {
				this.entityManager.merge(this.getInstance());
			}
		} catch (final Exception e) {
			JSFUtil.sendWarnMessageToUser("MSG023");
			return null;
		}

		JSFUtil.sendInfoMessageToUser("MSG015");
		return this.getListView();
	}

	public String persist() {
		String redirect = null;
		try {
			if (this.getCrudManager() != null) {
				this.getCrudManager().inserir(this.getInstance());
			} else {
				this.entityManager.persist(this.getInstance());
			}
			JSFUtil.sendInfoMessageToUser("MSG015");
			redirect = this.getListView();
		} catch (final Exception e) {
			Throwable cause = e.getCause();
			if (cause instanceof PersistenceException) {
				JSFUtil.sendInfoMessageToUser("MSG009");
			} else {
				JSFUtil.sendWarnMessageToUser("MSG023");
			}
		}
		return redirect;
	}

	public String remove() {
		try {
			if (this.getCrudManager() != null) {
				this.getCrudManager().excluir(this.convert(this.getId()));
			} else {
				final E obj = this.entityManager.find(this.entityClass,
						this.convert(this.getId()));
				this.entityManager.remove(obj);
			}
			this.clearDataModel();
		} catch (final Exception e) {
			JSFUtil.sendWarnMessageToUser("MSG023");
		}

		JSFUtil.sendInfoMessageToUser("MSG017");
		return this.getListView();
	}

	public String remove(final ID id) {
		try {
			if (this.getCrudManager() != null) {
				this.getCrudManager().excluir(id);
			} else {
				final E obj = this.entityManager.find(this.entityClass, id);
				this.entityManager.remove(obj);
			}
			this.clearDataModel();
		} catch (final Exception e) {
			JSFUtil.sendWarnMessageToUser("MSG023");
		}

		JSFUtil.sendInfoMessageToUser("MSG017");
		return null;
	}

	public String update() {
		String redirect = null;
		try {
			if (this.getCrudManager() != null) {
				this.getCrudManager().alterar(this.getInstance());
			} else {
				this.entityManager.merge(this.getInstance());
			}
			JSFUtil.sendInfoMessageToUser("MSG017");
			redirect = this.getListView();
		} catch (final Exception e) {
			JSFUtil.sendWarnMessageToUser("MSG023");
		}
		return redirect;
	}

	public DataModel<E> getDataModel() {
		if (this.dataModel == null) {
			if (this.isAutoSearch() || (this.resultList != null)) {
				this.resultList = this.handleResultList();
			}

			if (this.resultList == null) {
				this.resultList = new ArrayList<E>();
			}

			this.dataModel = new ListDataModel<E>(this.resultList);
		}

		return this.dataModel;
	}

	public List<E> search() {
		this.clearDataModel();
		return this.handleResultList();
	}

	public void setAutoSearch(final boolean autoSearch) {
		this.autoSearch = autoSearch;
	}

	public void setDataTable(final DataTable dataTable) {
		this.dataTable = dataTable;
	}

	public void setId(final String id) {
		this.id = id;
	}

	public void setInstance(final E instance) {
		this.instance = instance;
	}

	public void setResultList(final List<E> resultList) {
		this.resultList = resultList;
	}

	public void setDataModel(DataModel<E> dataModel) {
		this.dataModel = dataModel;
	}

	public boolean isAutoSearch() {
		return autoSearch;
	}

}
